package dao

import (
	"errors"
	"fmt"
	"goods-srv/internal/model"
	"goods-srv/libs"
)

type IGoods interface {
	CreateGoodsSku(goodsSkuList []model.GoodsSku) (err error)
	DeductionStock(goodsSkuList []model.GoodsSku) (err error)
	IncreaseStock(goodsSkuList []model.GoodsSku) (err error)
}

type Goods struct {
}

func (_ Goods) CreateGoodsSku(goodsSkuList []model.GoodsSku) (err error) {
	for i := 0; i < len(goodsSkuList); i++ {
		goodsSkuList[i].Id = libs.GetId()
	}
	db := libs.GetDB()
	result := db.Create(goodsSkuList)
	if result.Error != nil {
		return err
	}
	return nil
}

// DeductionStock 扣减库存
func (_ Goods) DeductionStock(goodsSkuList []model.GoodsSku) (err error) {
	db := libs.GetDB()
	// 创建一个用于获取互斥锁的再同步实例。
	rs := libs.GetRedsync()

	// 开启事务
	tx := db.Begin()

	for _, v := range goodsSkuList {
		// 1.创建互斥锁对象
		mutex := rs.NewMutex(fmt.Sprintf("DeductionStock-%d", v.Id)) // 设置name，唯一
		// 2.获取锁
		if err = mutex.Lock(); err != nil {
			// 回滚事务
			tx.Rollback()
			return errors.New("获取分布式锁异常")
		}

		// 3.查询商品库存
		goodsSku := model.GoodsSku{}
		// 查
		result := db.First(&goodsSku, v.Id)
		if result.Error != nil {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return result.Error
		}
		if result.RowsAffected == 0 {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return errors.New("没有库存信息")
		}

		if goodsSku.Stock == 0 {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return errors.New("暂无库存")
		}

		if goodsSku.Stock < v.Stock {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return errors.New("库存不足")
		}

		// 4.执行扣减
		goodsSku.Stock = goodsSku.Stock - v.Stock

		// 5.更新
		result = tx.Save(&goodsSku)
		if result.Error != nil {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return result.Error
		}

		// 6.释放锁
		if ok, err := mutex.Unlock(); !ok || err != nil {
			// 回滚事务
			tx.Rollback()
			return errors.New("释放锁失败")
		}
	}

	tx.Commit() // 提交修改
	return nil
}

// IncreaseStock 增加库存
func (_ Goods) IncreaseStock(goodsSkuList []model.GoodsSku) (err error) {
	db := libs.GetDB()
	// 创建一个用于获取互斥锁的再同步实例。
	rs := libs.GetRedsync()

	// 开启事务
	tx := db.Begin()

	for _, v := range goodsSkuList {
		// 1.创建互斥锁对象
		mutex := rs.NewMutex(fmt.Sprintf("IncreaseStock-%d", v.Id)) // 设置name，唯一
		// 2.获取锁
		if err = mutex.Lock(); err != nil {
			// 回滚事务
			tx.Rollback()
			return errors.New("获取分布式锁异常")
		}

		// 3.查询商品库存
		goodsSku := model.GoodsSku{}
		// 查
		result := db.First(&goodsSku, v.Id)
		if result.Error != nil {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return result.Error
		}
		if result.RowsAffected == 0 {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return errors.New("没有库存信息")
		}

		// 4.执行累加
		goodsSku.Stock = goodsSku.Stock + v.Stock

		// 5.更新
		result = tx.Save(&goodsSku)
		if result.Error != nil {
			// 回滚事务
			tx.Rollback()
			// 释放锁
			if ok, err := mutex.Unlock(); !ok || err != nil {
				return errors.New("释放锁失败")
			}
			return result.Error
		}

		// 6.释放锁
		if ok, err := mutex.Unlock(); !ok || err != nil {
			// 回滚事务
			tx.Rollback()
			return errors.New("释放锁失败")
		}
	}

	tx.Commit() // 提交修改
	return nil
}

func NewGoods() IGoods {
	return Goods{}
}
